﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics; 

using DupeKill.Core;
using DupeKill.Core.IO; 
using DupeKill.Core.Discovery;
using DupeKill.Core.Reporting;
using System.IO;  

namespace DupeKill
{
    class Program
    {
        private const int CHUNK_SIZE = 4096; 

        static void Main(string[] args)
        {
            Trace.Listeners.Add(new ConsoleTraceListener());

            bool scan = false;
            bool kill = false;
            bool keepFirstOnly = false; 
            string reportXmlFile = null;
            string inputDirectory = null; 

            Trace.WriteLine("DupeKill");      
            scan = args[0].ToLower() == "--scan";
            kill = args[0].ToLower() == "--kill";

            for (int i = 1; i < args.Length; i++)
            {
                if(args[i].ToLower() == "--directory")
                {
                    if (i + 1 < args.Length)
                    {
                        inputDirectory = args[i + 1];
                        i++; 
                    }
                }
                if (args[i].ToLower() == "--report")
                {
                    if (i + 1 < args.Length)
                    {
                        reportXmlFile = args[i + 1];
                        i++;
                    }
                }
                if (args[i].ToLower() == "--keepfirstonly")
                {
                    keepFirstOnly = true; 
                }
            }

            if (scan)
            {
                if (inputDirectory == null)
                {
                    Trace.WriteLine("Invalid Arguments");
                    return; 
                }

                IReportGenerator reportGenerator = null;
                if (reportXmlFile != null)
                    reportGenerator = new XmlReportGenerator(reportXmlFile);
                else
                    reportGenerator = new NullReportGenerator();

                IFileIterator iterator = FileIteratorFactory.Create(inputDirectory);
                IFileSystemGateway gateway = FileSystemGatewayFactory.Create();
                FileSetComputation fileSetComputation = new FileSetComputation(iterator, gateway, CHUNK_SIZE);

                Stopwatch sw = new Stopwatch();
                sw.Start();

                foreach (FileSet fileSet in fileSetComputation.Compute())
                {
                    reportGenerator.Append(fileSet);
                    if (fileSet.Count > 1)
                    {
                        Trace.WriteLine(string.Format("Found a set of {0} duplicates : ", fileSet.Count));
                        Trace.WriteLine("---------------------------------");

                        for (int i = 0; i < fileSet.Count; i++)
                        {
                            Trace.WriteLine(string.Format("\t {0} \t size {1}", fileSet[i].FullPath, fileSet[i].Length));
                        }
                    }
                }
                sw.Stop();
                reportGenerator.Flush();
                Trace.WriteLine(string.Format("Search completed in {0}.", sw.Elapsed));
            }
            else if (kill)
            {
                if (reportXmlFile == null)
                {
                    Trace.WriteLine("Invalid Arguments");
                    return; 
                }

                Trace.WriteLine("Loading report..."); 
                List<FileSet> fileSets = new List<FileSet>(new XmlReportFileSetLoader().LoadAll(reportXmlFile));

                for (int i = 0; i < fileSets.Count; i++)
                {
                    FileSet fileSet = fileSets[i];

                    Trace.WriteLine(string.Format("File-Set {0} of {1}", i + 1, fileSets.Count));
                    Trace.WriteLine("------------------------");

                    for (int j = 0; j < fileSet.Count; j++)
                    {
                        Trace.WriteLine(string.Format("[{0}] : {1}", j, fileSet[j].FullPath)); 
                    }

                    FileSet filesToKeep = new FileSet();

                    if (keepFirstOnly)
                    {
                        filesToKeep.Add(fileSet[0]); 
                    }
                    else
                    {
                        Trace.WriteLine("Enter file numbers to keep, separated by colon (a:all,q:quit)");
                        string input = Console.ReadLine();

                        if (input == "q")
                        {
                            return;
                        }
                        else if (input == "a")
                        {
                            filesToKeep = fileSet;
                        }
                        else if (input != "a")
                        {
                            string[] keepList = input.Split(',');
                            int[] keep = new int[keepList.Length];

                            for (int k = 0; k < keepList.Length; k++)
                                keep[k] = int.Parse(keepList[k]);

                            for (int l = 0; l < fileSet.Count; l++)
                            {
                                if (Array.Exists(keep, x => x == l))
                                {
                                    filesToKeep.Add(fileSet[l]);
                                }
                            }
                        }
                    }

                    foreach (FileInformation file in fileSet)
                    {
                        if (!filesToKeep.Contains(file) && File.Exists(file.FullPath))
                        {
                            try
                            {
                                File.Delete(file.FullPath);
                                Trace.WriteLine(string.Format("Deleted {0}", file.FullPath));
                            }
                            catch(Exception e)
                            {
                                Trace.WriteLine(string.Format("Could not delete file {0} : {1}", file.FullPath, e.Message)); 
                            }
                        }
                    }
                }

            }

            Trace.Flush();
            Console.Read(); 
        }
    }
}
